home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Sprite 1984 - 1993
/
Sprite 1984 - 1993.iso
/
src
/
kernel
/
net
/
ds3100.md
/
netLERecv.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-12-18
|
10KB
|
360 lines
/* netLERecv.c -
*
* Routines to manage the receive unit of the AMD LANCE ethernet chip.
*
* Copyright (C) 1989 Digital Equipment Corporation.
* Permission to use, copy, modify, and distribute this software and
* its documentation for any purpose and without fee is hereby granted,
* provided that the above copyright notice appears in all copies.
* Digital Equipment Corporation makes no representations about the
* suitability of this software for any purpose. It is provided "as is"
* without express or implied warranty.
*/
#ifndef lint
static char rcsid[] = "$Header: /cdrom/src/kernel/Cvsroot/kernel/net/ds3100.md/netLERecv.c,v 9.2 90/11/05 18:09:45 jhh Exp $ SPRITE (DECWRL)";
#endif not lint
#include <sprite.h>
#include <vm.h>
#include <netLEInt.h>
#include <sys.h>
#include <list.h>
#include <machMon.h>
/*
* Macro to step ring pointers.
*/
#define NEXT_RECV(p) ((p) == statePtr->recvDescLastPtr) ? \
statePtr->recvDescFirstPtr : \
(Address)BUF_TO_ADDR(p, NET_LE_RECV_DESC_SIZE)
/*
*----------------------------------------------------------------------
*
* AllocateRecvMem --
*
* Allocate kernel memory for receive ring and data buffers.
*
* Results:
* None.
*
* Side effects:
* Device state structure is updated.
*
*----------------------------------------------------------------------
*/
static void
AllocateRecvMem(statePtr)
NetLEState *statePtr; /* The state of the interface. */
{
int i;
/*
* Allocate the ring of receive buffer descriptors. The ring must start
* on 8-byte boundary.
*/
statePtr->recvDescFirstPtr =
NetLEMemAlloc(NET_LE_NUM_RECV_BUFFERS * NET_LE_RECV_DESC_SIZE, FALSE);
/*
* Allocate the receive buffers.
*/
for (i = 0; i < NET_LE_NUM_RECV_BUFFERS; i++) {
statePtr->recvDataBuffer[i] =
NetLEMemAlloc(NET_LE_RECV_BUFFER_SIZE, TRUE);
}
statePtr->recvMemAllocated = TRUE;
/*
* Allocate memory for the buffer to copy packets into after we
* receive them.
*/
statePtr->recvBufPtr = (Address) malloc(NET_LE_RECV_BUFFER_SIZE + 2);
/*
* 2 byte align the recvBufPtr so that we can 4 byte align all words
* after the ethernet header.
*/
statePtr->recvBufPtr += 2;
}
/*
*----------------------------------------------------------------------
*
* NetLERecvInit --
*
* Initialize the receive buffer lists for the receive unit allocating
* memory if need.
*
* Results:
* None.
*
* Side effects:
* The receive ring is initialized and the device state structure is
* updated.
*
*----------------------------------------------------------------------
*/
void
NetLERecvInit(statePtr)
NetLEState *statePtr; /* The state of the interface. */
{
int bufNum;
Address descPtr;
if (!statePtr->recvMemAllocated) {
AllocateRecvMem(statePtr);
}
/*
* Initialize the state structure to point to the ring. recvDescFirstPtr
* is set by AllocateRecvMem() and never changed.
*/
statePtr->recvDescLastPtr = (Address)
BUF_TO_ADDR(statePtr->recvDescFirstPtr,
(NET_LE_NUM_RECV_BUFFERS - 1) * NET_LE_RECV_DESC_SIZE);
statePtr->recvDescNextPtr = statePtr->recvDescFirstPtr;
/*
* Initialize the ring buffer descriptors.
*/
descPtr = statePtr->recvDescFirstPtr;
for (bufNum = 0;
bufNum < NET_LE_NUM_RECV_BUFFERS;
bufNum++, descPtr += 2 * NET_LE_RECV_DESC_SIZE) {
/*
* Point the descriptor at its buffer.
*/
*BUF_TO_ADDR(descPtr,NET_LE_RECV_BUF_SIZE) =
-NET_LE_RECV_BUFFER_SIZE;
*BUF_TO_ADDR(descPtr,NET_LE_RECV_BUF_ADDR_LOW) =
BUF_TO_CHIP_ADDR(statePtr->recvDataBuffer[bufNum]) &
0xFFFF;
*BUF_TO_ADDR(descPtr,NET_LE_RECV_STATUS) =
((BUF_TO_CHIP_ADDR(statePtr->recvDataBuffer[bufNum]) >> 16) &
NET_LE_RECV_BUF_ADDR_HIGH) |
NET_LE_RECV_START_OF_PACKET |
NET_LE_RECV_END_OF_PACKET |
NET_LE_RECV_CHIP_OWNED;
}
descPtr = statePtr->recvDescFirstPtr;
statePtr->recvMemInitialized = TRUE;
}
/*
*----------------------------------------------------------------------
*
* NetLERecvProcess --
*
* Process a newly received packet.
*
* Results:
* FAILURE if something went wrong, SUCCESS otherwise.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
ReturnStatus
NetLERecvProcess(dropPackets, statePtr)
Boolean dropPackets; /* Drop all packets. */
NetLEState *statePtr; /* The state of the interface. */
{
register Address descPtr;
register volatile short *inBufPtr;
register short *outBufPtr;
register unsigned status;
register int i;
int size;
Boolean tossPacket;
/*
* If not initialized then forget the interrupt.
*/
if (!statePtr->recvMemInitialized) {
return (FAILURE);
}
descPtr = (Address)statePtr->recvDescNextPtr;
status = *BUF_TO_ADDR(descPtr,NET_LE_RECV_STATUS);
/*
* First a few consistency check.
*/
if (status & NET_LE_RECV_CHIP_OWNED) {
printf("LE ethernet: Bogus receive interrupt. Buffer owned by chip.\n");
return (FAILURE);
}
if (!(status & NET_LE_RECV_START_OF_PACKET)) {
printf(
"LE ethernet: Bogus receive interrupt. Buffer doesn't start packet.\n");
return (FAILURE);
}
/*
* Loop as long as there are packets to process.
*/
tossPacket = dropPackets;
while (TRUE) {
/*
* Check to see if we have processed all our buffers.
*/
if (status & NET_LE_RECV_CHIP_OWNED) {
break;
}
/*
* Since we allocated very large receive buffers all packets must fit
* in one buffer. Hence all buffers should have startOfPacket.
*/
if (!(status & NET_LE_RECV_START_OF_PACKET)) {
printf("LE ethernet: Receive buffer doesn't start packet.\n");
return (FAILURE);
}
/*
* All buffers should also have an endOfPacket too.
*/
if (!(status & NET_LE_RECV_END_OF_PACKET)) {
/*
* If not an endOfPacket see if it was an error packet.
*/
if (!(status & NET_LE_RECV_ERROR)) {
printf("LE ethernet: Receive buffer doesn't end packet.\n");
return (FAILURE);
}
/*
* We have got a serious error with a packet.
* Report the error and toss the packet.
*/
tossPacket = TRUE;
if (status & NET_LE_RECV_OVER_FLOW_ERROR) {
statePtr->stats.overrunErrors++;
printf("LE ethernet: Received packet with overflow error.\n");
}
/*
* Should probably panic on buffer errors.
*/
if (status & NET_LE_RECV_BUFFER_ERROR) {
panic("LE ethernet: Received packet with buffer error.\n");
}
} else {
/*
* The buffer had an endOfPacket bit set. Check for CRC errors and
* the like.
*/
if (status & NET_LE_RECV_ERROR) {
tossPacket = TRUE; /* Throw away packet on error. */
if (status & NET_LE_RECV_FRAMING_ERROR) {
statePtr->stats.frameErrors++;
printf(
"LE ethernet: Received packet with framing error.\n");
}
if (status & NET_LE_RECV_CRC_ERROR) {
statePtr->stats.crcErrors++;
printf("LE ethernet: Received packet with CRC error.\n");
}
}
}
/*
* Once we gotten here, it means that the buffer contains a packet
* and the tossPacket flags says if it is good or not.
*/
statePtr->stats.packetsRecvd++;
/*
* Remove the CRC check (4 bytes) at the end of the packet.
*/
size = *BUF_TO_ADDR(descPtr, NET_LE_RECV_PACKET_SIZE) - 4;
/*
* Copy the data out.
*/
inBufPtr = (volatile short *) CHIP_TO_BUF_ADDR(
*BUF_TO_ADDR(descPtr,NET_LE_RECV_BUF_ADDR_LOW) |
((*BUF_TO_ADDR(descPtr,NET_LE_RECV_STATUS) &
NET_LE_RECV_BUF_ADDR_HIGH) << 16));
#define COPY_IN(n) *(outBufPtr + n) = *(inBufPtr + (2 * n))
outBufPtr = (short *)statePtr->recvBufPtr;
i = size;
while (i >= 64) {
COPY_IN(0); COPY_IN(1); COPY_IN(2); COPY_IN(3);
COPY_IN(4); COPY_IN(5); COPY_IN(6); COPY_IN(7);
COPY_IN(8); COPY_IN(9); COPY_IN(10); COPY_IN(11);
COPY_IN(12); COPY_IN(13); COPY_IN(14); COPY_IN(15);
COPY_IN(16); COPY_IN(17); COPY_IN(18); COPY_IN(19);
COPY_IN(20); COPY_IN(21); COPY_IN(22); COPY_IN(23);
COPY_IN(24); COPY_IN(25); COPY_IN(26); COPY_IN(27);
COPY_IN(28); COPY_IN(29); COPY_IN(30); COPY_IN(31);
outBufPtr += 32;
inBufPtr += 64;
i -= 64;
}
while (i >= 16) {
COPY_IN(0); COPY_IN(1); COPY_IN(2); COPY_IN(3);
COPY_IN(4); COPY_IN(5); COPY_IN(6); COPY_IN(7);
outBufPtr += 8;
inBufPtr += 16;
i -= 16;
}
while (i > 0) {
*outBufPtr = *inBufPtr;
outBufPtr++;
inBufPtr += 2;
i -= 2;
}
/*
* Call higher level protocol to process the packet.
*/
if (!tossPacket) {
Net_Input(statePtr->interPtr,(Address)statePtr->recvBufPtr, size);
}
/*
* We're finished with it, give the buffer back to the chip.
*/
*BUF_TO_ADDR(descPtr,NET_LE_RECV_STATUS) |= NET_LE_RECV_CHIP_OWNED;
/*
* Clear the interrupt bit for the packet we just got before
* we check the ownership of the next packet. This prevents the
* following race condition: We check the buffer and it is own
* by the chip; the chip gives the buffer to us and sets the
* interrupt; we clear the interrupt.
* The fix is to always clear the interrupt and then check
* for owership as the chip sets owership and then sets the
* interrupt.
*/
*statePtr->regAddrPortPtr = NET_LE_CSR0_ADDR;
*statePtr->regDataPortPtr =
NET_LE_CSR0_RECV_INTR | NET_LE_CSR0_INTR_ENABLE;
/*
* Check to see if we have processed all our buffers.
*/
descPtr = NEXT_RECV(descPtr);
status = *BUF_TO_ADDR(descPtr,NET_LE_RECV_STATUS);
if (status & NET_LE_RECV_CHIP_OWNED) {
break;
}
}
/*
* Update the the ring pointer. We should be pointer at the chip owned
* buffer in that the next packet will be put.
*/
statePtr->recvDescNextPtr = descPtr;
/*
* RETURN a success.
*/
return (SUCCESS);
}